// Copyright Epic Games, Inc. All Rights Reserved.

#include "Abilities/AbilityTask_TestNetworkSyncPoint.h"
#include "AbilitySystemComponent.h"
#include "Abilities/TestAbilitySystemComponent.h"

UAbilityTask_TestNetworkSyncPoint::UAbilityTask_TestNetworkSyncPoint()
	:PayloadVector(0.f, 0.f, 0.f)
{
	ReplicatedEventToListenFor = EAbilityGenericReplicatedEvent::MAX;
}

void UAbilityTask_TestNetworkSyncPoint::OnSignalCallback()
{
	FVector_NetQuantize100 ReplicatedPayloadVector = {FVector::ZeroVector};
	
	if (AbilitySystemComponent)
	{
		AbilitySystemComponent->ConsumeGenericReplicatedEvent(ReplicatedEventToListenFor, GetAbilitySpecHandle(), GetActivationPredictionKey());
		const auto ReplicatedData = AbilitySystemComponent->GetReplicatedDataOfGenericReplicatedEvent(ReplicatedEventToListenFor, GetAbilitySpecHandle(), GetActivationPredictionKey());
		ReplicatedPayloadVector = ReplicatedData.VectorPayload;
	}
	SyncFinished(ReplicatedPayloadVector);
}

UAbilityTask_TestNetworkSyncPoint* UAbilityTask_TestNetworkSyncPoint::TestWaitNetSync(class UGameplayAbility* OwningAbility, EAbilityTaskNetSyncType InSyncType, FVector_NetQuantize100 InPayloadVector)
{
	UAbilityTask_TestNetworkSyncPoint* MyObj = NewAbilityTask<UAbilityTask_TestNetworkSyncPoint>(OwningAbility);
	MyObj->SyncType = InSyncType;
	MyObj->PayloadVector = InPayloadVector;
	return MyObj;
}

void UAbilityTask_TestNetworkSyncPoint::Activate()
{
	FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent, IsPredictingClient());

	if (UTestAbilitySystemComponent* TestAbilitySystemComponent = Cast<UTestAbilitySystemComponent>(AbilitySystemComponent))
	{
		if (IsPredictingClient())
		{
			if (SyncType != EAbilityTaskNetSyncType::OnlyServerWait )
			{
				// As long as we are waiting (!= OnlyServerWait), listen for the GenericSignalFromServer event
				ReplicatedEventToListenFor = EAbilityGenericReplicatedEvent::GameCustom2;
			}
			if (SyncType != EAbilityTaskNetSyncType::OnlyClientWait)
			{
				// As long as the server is waiting (!= OnlyClientWait), send the Server and RPC for this signal
				TestAbilitySystemComponent->ServerSetReplicatedEventWithPayload(EAbilityGenericReplicatedEvent::GameCustom1, GetAbilitySpecHandle(), GetActivationPredictionKey(), AbilitySystemComponent->ScopedPredictionKey, PayloadVector);
			}
			
		}
		else if (IsForRemoteClient())
		{
			if (SyncType != EAbilityTaskNetSyncType::OnlyClientWait )
			{
				// As long as we are waiting (!= OnlyClientWait), listen for the GenericSignalFromClient event
				ReplicatedEventToListenFor = EAbilityGenericReplicatedEvent::GameCustom1;
			}
			if (SyncType != EAbilityTaskNetSyncType::OnlyServerWait)
			{
				// As long as the client is waiting (!= OnlyServerWait), send the Server and RPC for this signal
				TestAbilitySystemComponent->ClientSetReplicatedEventWithPayload(EAbilityGenericReplicatedEvent::GameCustom2, GetAbilitySpecHandle(), GetActivationPredictionKey(), PayloadVector);
			}
		}

		if (ReplicatedEventToListenFor != EAbilityGenericReplicatedEvent::MAX)
		{
			CallOrAddReplicatedDelegate(ReplicatedEventToListenFor, FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &UAbilityTask_TestNetworkSyncPoint::OnSignalCallback));
		}
		else
		{
			// We aren't waiting for a replicated event, so the sync is complete.
			SyncFinished(PayloadVector);
		}
	}
}

void UAbilityTask_TestNetworkSyncPoint::SyncFinished(const FVector_NetQuantize100 InPayloadVector)
{
	if (!IsPendingKill())
	{
		if (ShouldBroadcastAbilityTaskDelegates())
		{
			OnSync.Broadcast(InPayloadVector);
		}
		EndTask();
	}
}
